package the.broccoli.uc.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import org.apache.commons.lang.RandomStringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.wisteria.framework.util.DateUtils;
import org.wisteria.framework.util.TextUtils;
import org.wisteria.framework.web.BusinessException;
import org.wisteria.framework.web.mvc.constant.WebConsts;
import org.wisteria.framework.web.mvc.service.AbstractSuperService;
import the.broccoli.auth.SessionUser;
import the.broccoli.auth.UserContext;
import the.broccoli.setting.service.IParamsService;
import the.broccoli.uc.constant.RoleType;
import the.broccoli.uc.constant.UCErrorCodeConsts;
import the.broccoli.uc.constant.UCConsts;
import the.broccoli.uc.dto.AdminUserAddDTO;
import the.broccoli.uc.dto.Secret;
import the.broccoli.uc.entity.*;
import the.broccoli.uc.mapper.UserMapper;
import the.broccoli.uc.service.*;
import the.broccoli.uc.vo.UserCondition;

import java.time.LocalDateTime;
import java.util.Date;
import java.util.List;

/**
 * <p>
 * 用户 服务实现类
 * </p>
 */
@Service
public class UserServiceImpl extends AbstractSuperService<UserMapper, User> implements IUserService {

    @Autowired
    private ITenantService tenantService;

    @Autowired
    private IRoleService roleService;

    @Autowired
    private IUserRoleService userRoleService;

    @Autowired
    private IParamsService paramsService;

    @Autowired
    private ITenantAppService tenantAppService;

    /**
     * 新增管理员账号
     */
    @Override
    public boolean addAdminUser(AdminUserAddDTO dto) {
        User user = new User();
        user.setTenantId(dto.getTenantId());
        user.setAccount(dto.getAccount());
        user.setUserName(dto.getUserName());
        user.setCreatedId(dto.getOperatorId());
        user.setCreatedName(dto.getOperatorName());
        user.setCreatedTime(new Date());
        user.setModifiedId(dto.getOperatorId());
        user.setModifiedName(dto.getOperatorName());
        user.setModifiedTime(new Date());
        int result = baseMapper.insert(user);
        if (result > 0) {
            updatePassword(user.getUserId(), dto.getPassword(), dto.getOperatorId(), dto.getOperatorName());
        }

        UserRole userRole = new UserRole();
        userRole.setRoleId(dto.getRoleId());
        userRole.setUserId(user.getUserId());
        userRole.setCreatedId(dto.getOperatorId());
        userRole.setCreatedName(dto.getOperatorName());
        userRole.setCreatedTime(new Date());
        userRole.setModifiedId(dto.getOperatorId());
        userRole.setModifiedName(dto.getOperatorName());
        userRole.setModifiedTime(new Date());
        userRoleService.save(userRole);
        return true;
    }

    /**
     * 保存管理账号信息
     * @param account       登录账号
     * @param userName      用户名称
     * @param tenantId      租户ID
     * @param operatorId    操作人ID
     * @param operatorName  操作人名称
     */
    @Transactional
    @Override
    public User saveAdmin(String account, String userName, Integer tenantId, String operatorId, String operatorName) {
        User user = new User();
        user.setTenantId(tenantId);
        user.setAccount(account);
        user.setUserName(userName);
        user.setCreatedId(operatorId);
        user.setCreatedName(operatorName);
        user.setCreatedTime(new Date());
        String password = paramsService.getValue(UCConsts.DEFAULT_PASSWORD_CODE);
        saveAndCheck(user, StringUtils.hasText(password) ? password : account);

        Role role = new Role();
        role.setTenantId(tenantId);
        role.setRoleType(RoleType.admin.name());
        role.setRoleName(RoleType.admin.title());
        role.setParentId(WebConsts.ROOT);
        role.setCreatedId(operatorId);
        role.setCreatedName(operatorName);
        role.setCreatedTime(new Date());
        roleService.save(role);

        UserRole userRole = new UserRole();
        userRole.setUserId(user.getUserId());
        userRole.setRoleId(role.getRoleId());
        userRole.setCreatedId(operatorId);
        userRole.setCreatedName(operatorName);
        userRole.setCreatedTime(new Date());
        userRoleService.save(userRole);
        return user;
    }

    /**
     * 新增用户，手机号码作为登录账号，并创建默认租户并关联默认应用
     *
     * @param account      账号
     * @param userName     用户名
     * @param tenantName   租户名称
     * @param operatorId   操作人ID
     * @param operatorName 操作人名称
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public User save(String account, String userName, String tenantName, String operatorId, String operatorName) {
        return save(account, userName, null, tenantName, operatorId, operatorName);
    }

    /**
     * 新增用户，用户的登录账号为账号，手机号码，并创建默认租户并关联默认应用
     *
     * @param account      账号
     * @param userName     用户名
     * @param phone        手机号码
     * @param tenantName
     * @param operatorId   操作人ID
     * @param operatorName 操作人名称
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public User save(String account, String userName, String phone, String tenantName, String operatorId, String operatorName) {
        Tenant tenant = new Tenant();
        tenant.setTenantName(tenantName);
        tenant.setCreatedId(operatorId);
        tenant.setCreatedName(operatorName);
        tenant.setCreatedTime(new Date());
        tenantService.save(tenant);

        String defaultAppId = paramsService.getValue(UCConsts.DEFAULT_APP_ID);
        TenantApp tenantApp = new TenantApp();
        tenantApp.setTenantId(tenant.getTenantId());
        tenantApp.setAppId(StringUtils.hasText(defaultAppId) ? Integer.parseInt(defaultAppId) : null);
        tenant.setCreatedId(operatorId);
        tenant.setCreatedName(operatorName);
        tenant.setCreatedTime(new Date());
        tenantAppService.save(tenantApp);

        User user = new User();
        user.setTenantId(tenant.getTenantId());
        user.setAccount(account);
        user.setPhone(phone);
        user.setUserName(userName);
        user.setCreatedId(operatorId);
        user.setCreatedName(operatorName);
        user.setCreatedTime(new Date());
        String password = paramsService.getValue(UCConsts.DEFAULT_PASSWORD_CODE);
        saveAndCheck(user, StringUtils.hasText(password) ? password : account);

        Role role = new Role();
        role.setTenantId(tenant.getTenantId());
        role.setRoleType(RoleType.admin.name());
        role.setRoleName(RoleType.admin.title());
        role.setParentId(WebConsts.ROOT);
        role.setCreatedId(operatorId);
        role.setCreatedName(operatorName);
        role.setCreatedTime(new Date());
        roleService.save(role);

        UserRole userRole = new UserRole();
        userRole.setUserId(user.getUserId());
        userRole.setRoleId(role.getRoleId());
        userRole.setCreatedId(operatorId);
        userRole.setCreatedName(operatorName);
        userRole.setCreatedTime(new Date());
        userRoleService.save(userRole);

        return user;
    }

    /**
     * 检验并新增用户
     *
     * @param entity 用户信息
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveAndCheck(User entity) {
        if (!StringUtils.hasText(entity.getAccount())
                && !StringUtils.hasText(entity.getPhone())
                && !StringUtils.hasText(entity.getEmail())) {
            throw BusinessException.withErrorCode(UCErrorCodeConsts.USER_LOGINACCOUNT_IS_NULL);
        }

//        if (StringUtils.hasText(entity.getAccount())
//                && baseMapper.selectByAccount(entity.getAccount()) != null) {
//            throw BusinessException.withErrorCode(UCErrorCodeConsts.USER_ACCOUNT_IS_EXIST);
//        }

        if (StringUtils.hasText(entity.getAccount())) {
            List<User> userList = baseMapper.selectList(new LambdaQueryWrapper<User>()
                    .eq(User::getTenantId, entity.getTenantId())
                    .eq(User::getAccount, entity.getAccount())
                    .eq(User::getUserType, entity.getUserType())
            );
            if (!CollectionUtils.isEmpty(userList)) {
                throw BusinessException.withMessage("账号已存在");
            }
        }

        save(entity);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveAndCheck(User entity, String password) {
        saveAndCheck(entity);
        updatePassword(entity.getUserId(), password, entity.getCreatedId(), entity.getModifiedName());
    }

    @Override
    public User getByLoginAccount(String loginAccount) {
        return baseMapper.selectByAccount(loginAccount);
    }

    @Override
    public Secret getByUserId(String userId) {
        return baseMapper.selectPassword(userId);
    }

    /**
     * 获取用户名
     *
     * @param userId 用户ID
     * @return
     */
    @Override
    public String getUserNameById(String userId) {
        User user = getById(userId);
        if (user == null) {
            return null;
        }
        return user.getUserName();
    }

    /**
     * 修改密码
     * @param userId        用户ID
     * @param password      密码
     * @param modifiedId    修改人ID
     * @param modifiedName  修改人名称
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updatePassword(String userId, String password, String modifiedId, String modifiedName) {
        String salt = RandomStringUtils.randomAscii(10);
        String md5Password = TextUtils.md5(password, salt);
        baseMapper.updatePassword(userId, md5Password, salt, modifiedId, modifiedName, new Date());
    }

    /**
     * 更新登录密码
     * @param userId        用户ID
     * @param oldPassword   旧密码
     * @param newPassword   新密码
     * @param modifiedId    修改人ID
     * @param modifiedName  修改人名称
     */
    @Override
    public void updatePassword(String userId, String oldPassword, String newPassword, String modifiedId, String modifiedName) {
        Secret secret = getByUserId(userId);
        if (secret != null && secret.getPassword().equals(TextUtils.md5(oldPassword, secret.getSalt()))) {
            updatePassword(userId, newPassword, modifiedId, modifiedName);
        }
    }

    /**
     * 根据用户类型查询用户列表
     * @return
     */
    @Override
    public List<User> listByUserType(String userType) {
        UserCondition condition = new UserCondition();
        // 普通账号的用户
        condition.setUserType(userType);
        condition.setTenantId(UserContext.tenantId());
        return listByCondition(condition);
    }

    /**
     * 获取会话信息
     * @param token 登录令牌
     * @return
     */
    @Override
    public SessionUser getSessionUser(String token) {
        User user = this.getById(token);
        if (user == null) {
            return null;
        }

        if (user.getLoginExpire() == null
                || LocalDateTime.now().isAfter(DateUtils.toLocalDateTime(user.getLoginExpire()))) {
            return null;
        }

        SessionUser sessionUser = new SessionUser();
        sessionUser.setUserId(user.getUserId());
        sessionUser.setOpenId(user.getOpenId());
        sessionUser.setAvatar(user.getAvatar());
        sessionUser.setToken(user.getUserId());
        sessionUser.setUserName(user.getUserName());
        sessionUser.setPhone(user.getPhone());
        return sessionUser;
    }

    /**
     * 更新登录失效时间
     * @param userId    用户ID
     * @return
     */
    @Override
    public boolean updateLoginExpire(String userId) {
        // 单位分钟
        int expireMinute = 60 * 24 * 7;
        String loginExpire = paramsService.getValue("wist.auth.login.expire");
        if (StringUtils.hasText(loginExpire)) {
            expireMinute = Integer.parseInt(loginExpire);
        }
        this.update(new LambdaUpdateWrapper<User>()
                .set(User::getLoginExpire, LocalDateTime.now().plusMinutes(expireMinute))
                .set(User::getModifiedTime, new Date())
                .eq(User::getUserId, userId)
        );
        return true;
    }

    /**
     * 根据unionId获取用户信息
     * @param unionId   用户ID
     * @return
     */
    @Override
    public User getByUnionId(String unionId) {
        List<User> dataList = baseMapper.selectList(new LambdaQueryWrapper<User>()
                .eq(User::getUnionId, unionId)
        );
        if (CollectionUtils.isEmpty(dataList)) {
            return null;
        }
        return dataList.get(0);
    }

}
